/*
 * j4Win
 *  http://code.google.com/p/j4win/
 *
 * Copyright (C) 2006-2007 Felix Geyer, Moritz Laschinger
 *
 * This file is part of j4Win.
 *
 * j4Win is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * version 2 as published by the Free Software Foundation.
 *
 * j4Win is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

package j4win;

public class Field implements Cloneable {
	private static final long serialVersionUID = 1L;
	
	public static final int WIDTH = 7;
	public static final int HEIGHT = 6;
	
	private transient int[][] field = new int[WIDTH][HEIGHT];
	
	public Field() {
		clear();
	}
	
	private Field(int[][] f) {
		field = f;
	}
	
	@Override
	public Field clone() {
		int[][] f = new int[WIDTH][HEIGHT];
		for (int x=0; x<WIDTH; ++x) {
			for (int y=0; y<HEIGHT; ++y) {
				f[x][y] = this.field[x][y];
			}
		}
		return new Field(f);
	}
	
	public int get(int x, int y) {
		return field[x][y];
	}
	
	public void set(int x, int y, int value) {
		assert x>=0 && x<WIDTH;
		assert y>=0 && y<HEIGHT;
		
		field[x][y] = value;
	}
	
	public int add(int x, int value) {
		assert x>=0 && x<WIDTH;
		
		for (int y=0; y<HEIGHT; ++y) {
			if (field[x][y] == 0) {
				field[x][y] = value;
				return y;
			}
		}
		
		throw new RuntimeException("Can't add stone, col full (x = "+x+")");
	}
	
	public void clear() {
		for (int x=0; x<WIDTH; ++x) {
			for (int y=0; y<HEIGHT; ++y) {
				field[x][y] = 0;
			}
		}
	}
	
	public boolean isEmpty() {
		for (int x=0; x<WIDTH; ++x) {
			for (int y=0; y<HEIGHT; ++y) {
				if (field[x][y]!=0)
					return false;
			}
		}
		
		return true;
	}
	
	public boolean isColFull(int x) {
		assert x>=0 && x<WIDTH;
		
		return field[x][HEIGHT-1] != 0;
	}
	
	public boolean isFull() {
		for (int x=0; x<WIDTH; ++x) {
			if (!isColFull(x)) return false;
		}
		
		return true;
	}
	
	public int getStonesLeft(int player) {
		int left = 21;
		
		for (int x=0; x<WIDTH; ++x) {
			for (int y=0; y<HEIGHT; ++y) {
				if (field[x][y]==player) --left;
				else if (field[x][y]==0) continue;
			}
		}
		
		return left;
	}
	
	public void swap() {
		for (int x=0; x<WIDTH; ++x) {
			for (int y=0; y<HEIGHT; ++y) {
				if (field[x][y]==1)
					field[x][y] = 2;
				else if (field[x][y]==2)
					field[x][y] = 1;
			}
		}
	}
	
	public static Field fromPacket(NetPacket p) {
		Field field = new Field();
		
		for (int x=0; x<WIDTH; ++x) {
			for (int y=0; y<HEIGHT; ++y) {
				field.set(x, y, p.readInt());
			}
		}
		
		return field;
	}
	
	public NetPacket toPacket() {
		NetPacket packet = new NetPacket(NetPacket.ID.Field);
		
		for (int x=0; x<WIDTH; ++x) {
			for (int y=0; y<HEIGHT; ++y) {
				packet.add(get(x, y));
			}
		}
		
		return packet;
	}
	
	public int lastStone(int x) {
		for (int y=0; y<HEIGHT; ++y) {
			if (get(x, y) == 0)
				return y-1;
		}
		
		return HEIGHT-1;
	}
	
	public boolean hasPlayerWon(int player, int lastX, int lastY) {
		int row;
		int x, y;
		
		// -
		row = 1;
		for (x=(lastX-1); x>=0; --x) {
			if (field[x][lastY]==player) ++row;
			else break;
		}
		for (x=(lastX+1); x<Field.WIDTH; ++x) {
			if (field[x][lastY]==player) ++row;
			else break;
		}
		if (row>=4) return true;
		
		// |
		row = 1;
		for (y=(lastY-1); y>=0; --y) {
			if (field[lastX][y]==player) ++row;
			else break;
		}
		// nothing above the last stone
		if (row>=4) return true;
		
		// /
		row = 1;
		x = lastX-1;
		y = lastY-1;
		while (x>=0 && y>=0) {
			if (field[x][y]==player) ++row;
			else break;
			
			--x;
			--y;
		}
		x = lastX+1;
		y = lastY+1;
		while (x<Field.WIDTH && y<Field.HEIGHT) {
			if (field[x][y]==player) ++row;
			else break;
			
			++x;
			++y;
		}
		if (row>=4) return true;
		
		// \
		row = 1;
		x = lastX+1;
		y = lastY-1;
		while (x<Field.WIDTH && y>=0) {
			if (field[x][y]==player) ++row;
			else break;
			
			++x;
			--y;
		}
		x = lastX-1;
		y = lastY+1;
		while (x>=0 && y<Field.HEIGHT) {
			if (field[x][y]==player) ++row;
			else break;
			
			--x;
			++y;
		}
		if (row>=4) return true;
		
		return false;
	}
}
